#include <iostream>
#include "raft.h"
#include "KvServer.h"
#include <unistd.h>
#include <iostream>
#include <random>

void ShowArgsHelp() {
    std::cout << "format: command -n <nodeNum> -f <configFileName>" << std::endl;
}

int main(int argc, char* argv[]) {
    // 步骤1：检查命令行参数数量，不足则显示帮助并退出
    if (argc < 2) {
        ShowArgsHelp();
        exit(EXIT_FAILURE);
    }

    // 步骤2：解析命令行参数（-n指定节点数量，-f指定配置文件路径）
    int c = 0;               // 用于接收getopt的返回值
    int nodeNum = 0;         // 集群节点数量
    std::string configFileName;  // 配置文件路径（存储节点信息）

    // 生成随机起始端口（10000-29999之间）：避免端口冲突，确保每个节点有唯一端口
    std::random_device rd;   // 随机数种子（硬件熵源）
    std::mt19937 gen(rd());  // 梅森旋转算法随机数生成器
    std::uniform_int_distribution<> dis(10000, 29999);  // 端口范围
    unsigned short startPort = dis(gen);  // 起始端口，后续节点端口依次递增

    // 使用getopt解析命令行选项（-n和-f）
    while ((c = getopt(argc, argv, "n:f:")) != -1) {
        switch (c) {
        case 'n':  // 处理节点数量参数
            nodeNum = atoi(optarg);  // 将字符串参数转为整数
            break;
        case 'f':  // 处理配置文件路径参数
            configFileName = optarg;
            break;
        default:   // 未知选项，显示帮助并退出
            ShowArgsHelp();
            exit(EXIT_FAILURE);
        }
    }

    // 步骤3：初始化配置文件（清空已有内容，为写入新节点信息做准备）
    // 先尝试打开文件并清空（trunc模式）
    std::ofstream file(configFileName, std::ios::out | std::ios::trunc);
    if (!file.is_open()) {  // 打开失败则报错退出
        std::cout << "无法打开配置文件 " << configFileName << std::endl;
        exit(EXIT_FAILURE);
    }
    file.close();  // 关闭文件，完成清空
    std::cout << "配置文件 " << configFileName << " 已清空，准备写入节点信息" << std::endl;

    // 步骤4：创建指定数量的节点进程（每个节点一个独立进程）
    for (int i = 0; i < nodeNum; i++) {
        short nodePort = startPort + static_cast<short>(i);  // 节点端口：起始端口 + 索引（确保唯一）
        std::cout << "开始创建KV节点：ID=" << i << "，端口=" << nodePort << "，父进程PID=" << getpid() << std::endl;

        pid_t pid = fork();  // 创建子进程（模拟独立节点）
        if (pid == 0) {
            // 子进程逻辑：初始化并运行KV服务器
            // 参数说明：i=节点ID，500=Raft选举超时时间（毫秒），configFileName=配置文件路径，nodePort=节点端口
            auto kvServer = new KvServer(i, 500, configFileName, nodePort);
            pause();  // 子进程暂停（阻塞等待信号，保持服务器运行状态，不退出）
        } 
        else if (pid > 0) {
            // 父进程逻辑：创建子进程后休眠1秒，避免节点启动冲突（如端口绑定竞争）
            sleep(1);
        } 
        else {
            // 进程创建失败：报错并退出
            std::cerr << "创建子进程失败（节点ID=" << i << "）" << std::endl;
            exit(EXIT_FAILURE);
        }
    }

    // 父进程最后暂停（保持运行，避免主进程退出导致子进程成为"孤儿进程"）
    pause();
    return 0;
}